package com.jia.sms.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.copier.CopyOptions;
import cn.hutool.core.lang.UUID;
import cn.hutool.core.util.RandomUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.jia.constant.RedisConstant;
import com.jia.sms.constants.PatternRegularConstant;
import com.jia.sms.constants.SmsRedisConstant;
import com.jia.sms.constants.UserConstant;
import com.jia.sms.dto.LoginFromDto;
import com.jia.sms.entity.User;
import com.jia.sms.mapper.UserMapper;
import com.jia.sms.service.UserService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpSession;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.regex.Pattern;

/**
 * (User)表服务实现类
 *
 * @author makejava
 * @since 2024-09-28 16:33:53
 */
@Slf4j
@Service("userService")
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {

    private final StringRedisTemplate stringRedisTemplate;

    public UserServiceImpl(StringRedisTemplate stringRedisTemplate) {
        this.stringRedisTemplate = stringRedisTemplate;
    }

    public static String REDIS_CODE_PREFIX = RedisConstant.PROJECT_REDIS_PREFIX
            + SmsRedisConstant.BUSINESS_SMS_PREFIX
            + SmsRedisConstant.CODE_PREFIX;

    public static String REDIS_TOKEN_PREFIX = RedisConstant.PROJECT_REDIS_PREFIX
            + SmsRedisConstant.BUSINESS_SMS_PREFIX
            + SmsRedisConstant.TOKEN_PREFIX;


    /**
     * 通过ID查询单条数据
     *
     * @param id 主键
     * @return 实例对象
     */
    @Override
    public User queryById(Long id) {
        return this.baseMapper.selectById(id);
    }

    /**
     * 分页查询
     *
     * @param user 筛选条件
     * @param page 分页对象
     * @return 查询结果
     */
    @Override
    public Page<User> queryByPage(User user, Page page) {
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        wrapper.eq(StringUtils.isNotEmpty(user.getPhone()), "phone", user.getPhone());
        wrapper.likeRight(StringUtils.isNotEmpty(user.getNickName()), "nick_name", user.getNickName());
        return this.baseMapper.selectPage(page, wrapper);
    }

    /**
     * 新增数据
     *
     * @param user 实例对象
     * @return 实例对象
     */
    @Override
    public User insert(User user) {
        this.baseMapper.insert(user);
        return user;
    }

    /**
     * 修改数据
     *
     * @param user 实例对象
     * @return 实例对象
     */
    @Override
    public User update(User user) {
        this.baseMapper.updateById(user);
        return this.queryById(user.getId());
    }

    /**
     * 通过主键删除数据
     *
     * @param id 主键
     * @return 是否成功
     */
    @Override
    public boolean deleteById(Long id) {
        return this.baseMapper.deleteById(id) > 0;
    }

    /**
     * 发送和保存验证码
     *
     * @param phone   手机号
     * @param session session
     */
    @Override
    public void sendCode(String phone, HttpSession session) {
        // 校验手机号
        validPhone(phone);
        // 生成验证码
        String code = RandomUtil.randomNumbers(6);
        // 使用session保存验证码
//        session.setAttribute("code", code);
        // 使用 redis 保存验证码
        stringRedisTemplate.opsForValue().set(REDIS_CODE_PREFIX + phone, code, 60, TimeUnit.SECONDS);
        // 保存验证码到session
        log.info("发送短信验证码成功，验证码：{}", code);
        // 返回ok
    }

    @Override
    public String login(LoginFromDto loginFromDto, HttpSession session) {
        String phone = loginFromDto.getPhone();
        // 校验手机号
        validPhone(phone);
        // 校验手机号
        // 从session中获取验证码
//        String code = (String) session.getAttribute("code");
        // 从redis中获取验证码
        String code = stringRedisTemplate.opsForValue().get(REDIS_CODE_PREFIX + phone);
        if (StringUtils.isEmpty(code) || !code.equalsIgnoreCase(loginFromDto.getCode())) {
            throw new RuntimeException("验证码不正确");
        }
        User user = query().eq("phone", phone).one();
        if (user == null) {
            //TODO 为了防止请求抖动 要加入幂等性策略
            User user1 = new User();
            user1.setPhone(phone);
            user1.setNickName(UserConstant.USER_PREFIX + phone);
            this.baseMapper.insert(user1);
            user = user1;
        }

        // 用户信息保存在session中
//        session.setAttribute("user", user);

        // 用户信息保存在redis中
        // 随机生成Token，作为登录令牌
        String token = UUID.randomUUID(true).toString();
        Map<String, Object> map = BeanUtil.beanToMap(user, new HashMap<>(),
                // 将字段的类型转为String存储
                CopyOptions.create().setIgnoreNullValue(true)
                        .setFieldValueEditor((fieldName, fieldValue) -> fieldValue.toString()));
        stringRedisTemplate.opsForHash().putAll(REDIS_TOKEN_PREFIX + token, map);
        // 设置token有效期
        stringRedisTemplate.expire(REDIS_TOKEN_PREFIX + token, 30, TimeUnit.MINUTES);
        log.info("登陆成功，用户：{}", user.getNickName());
        // 返回success
        return token;
    }


    public void validPhone(String phone) {
        if (StringUtils.isEmpty(phone)) {
            throw new RuntimeException("手机号不能为空");
        }
        final Pattern phonePattern = Pattern.compile(PatternRegularConstant.PHONE_PATTERN);
        if (!phonePattern.matcher(phone).matches()) {
            throw new RuntimeException("手机号不合法");
        }
    }

}
